#include "io_usart.h"

static UART_HandleTypeDef* IO_UART_Handle = NULL;

// 传入用于IO的串口句柄
void IO_USART_Init(UART_HandleTypeDef *handle) {
    IO_UART_Handle = handle;

    IO_USART_Show_Status();
}

int __io_putchar(int ch) {
    assert_param(IS_UART_INSTANCE(IO_UART_Handle->Instance));

    //在stm32H7上，DR寄存器被分为了TDR和RDR，SR寄存器同理
#ifdef STM32H7
    IO_UART_Handle->Instance->TDR = ch;
    while (!(IO_UART_Handle->Instance->ISR & UART_FLAG_TC));
#else
    IO_UART_Handle->Instance->DR = ch;
    while (!(IO_UART_Handle->Instance->SR & UART_FLAG_TC));
#endif
    return ch;
}

int __io_getchar(void){
    assert_param(IS_UART_INSTANCE(IO_UART_Handle->Instance));

    uint8_t tmp;
#ifdef STM32H7
    while (!(IO_UART_Handle->Instance->ISR & UART_FLAG_RXNE));
    tmp = IO_UART_Handle->Instance->RDR;
#else
    while (!(IO_UART_Handle->Instance->SR & UART_FLAG_RXNE));
    tmp = IO_UART_Handle->Instance->DR;
#endif
    return tmp;
}

// 从串口输入阻塞式的获取字符串，读到\n或len个字符结束，字符串存入pbuffer中
HAL_StatusTypeDef IO_USART_Get_String(char *pbuffer, int len) {
    if (pbuffer == NULL || len < 0)
        return HAL_ERROR;

    int i, tmp;
    char* ptr = pbuffer;
    for(i = 0; i < len; i++){
        tmp = __io_getchar();
        if(tmp == '\0' || tmp == '\n'){
            break;
        }
        *ptr++ = tmp;
    }
    *ptr = '\0';
    return HAL_OK;
}

HAL_StatusTypeDef IO_USART_Print_String(char *string) {
    if (string == NULL)
        return HAL_ERROR;

    char* ptr = string;
    while(*ptr){
        __io_putchar(*ptr++);
    }

    return HAL_OK;
}

uint32_t IO_USART_Get_Baudrate() {
    assert_param(IS_UART_INSTANCE(IO_UART_Handle->Instance));


    uint8_t USART_Prescale = READ_REG(IO_UART_Handle->Instance->PRESC);
    uint8_t Presclae_Index = USART_Prescale ? USART_Prescale * 2 : 1;
    uint32_t USART_BRR = READ_REG(IO_UART_Handle->Instance->BRR);
    uint32_t usart_key_ckpres = HAL_RCC_GetPCLK2Freq() / Presclae_Index;

    return usart_key_ckpres / USART_BRR;
}

void IO_USART_Show_Status() {
    assert_param(IS_UART_INSTANCE(IO_UART_Handle->Instance));

    uint32_t bdr = IO_USART_Get_Baudrate();
    printf("Current Baudrate: %lu\r\n", bdr);
}
